"""
1、任务介绍
     爬取豆瓣电影TOP250的基本信息：电影名称、豆瓣评分、评价数、电影概况、电影链接
     https://movie.douban.com/top250
2、爬虫初识
     按照一定的规则，根据用户需求，定向抓取互联网信息的程序或脚本
     本质是模拟浏览器打开网页，获取想要的数据
3、基本流程
   ① 准备工作
        通过浏览器查看分析目标网页
           cookie：需要登录的页面，要用到cookie
           user_agent：浏览器的版本
        学习编程基础规范
           一般python程序第一行需要加入： # -*-coding:utf-8-*-  或：
                                       # coding=utf-8
           使用函数实现单一功能或相关联功能的代码段，提高可读性和代码重复利用率
           加入main函数用于测试程序： if_name_=="_main_":
           使用#添加注释，说明代码的作用
        引入模块
           使用import导入模块
           from test import t1
           print(t1.add(1,2))
              test：directory-文件夹/包
              t1：python file-文件/模块
              t1.add()

           常用：import sys                          # 提供与python解释器及其环境有关的函数和变量
                import bs4                          # 网页解析，获取数据
                import re                           # 正则表达式，进行文字匹配
                import xlwt                         # 进行excel操作
                import urllib.request,urllib.error  # 制定URL，获取网页数据
                import sqlite3                      # 进行SQLite数据库操作
   ② 获取数据
        使用urllib库获取页面
   ③ 解析内容
        得到的可能是html、json等格式，可以用页面解析库、正则表达式进行解析
   ④ 保存数据
"""
from bs4 import BeautifulSoup
import re
import urllib.request, urllib.error
import xlwt
import sqlite3
import sys
def main():
    baseurl = "https://movie.douban.com/top250?start="
    # 1 爬取网页
    datalist = getData(baseurl)
    # 3 保存数据
    saveData(datalist)
    # askURL("https://movie.douban.com/top250?start=")

# 获取电影的各项规则
# 获取详情链接的规则
findLink = re.compile(r'<a href="(.*?)">')  # 创建正则表达式对象，表示规则（字符串的模式） .*表示所有的项目，？出现0次或1次，''里面有“”，所以用’‘框起来
# 图片
# findImgSrc = re.compile(r'<img alt="(.*?)" class="" src="(.*?)" width="(.*?)"/>', re.S)
findImgSrc = re.compile(r'<img.*src="(.*?)"', re.S)    # re.S：让换行符包含在字符中
# 片头-电影名称
findTitle = re.compile(r'<span class="title">(.*)</span>')
# 评分
findRating = re.compile(r'<span class="rating_num" property="v:average">(.*)</span>')
# 评价人数
findJudge = re.compile(r'<span>(\d*)人评价</span>')
# 一句话概况
findInq = re.compile(r'<span class="inq">(.*)</span>')
# 相关内容
findBd = re.compile(r'<p class="">(.*?)</p>', re.S)
# TODO 1 爬取网页

def getData(baseurl):
    datalist = []
    for i in range(0, 10):
        url = baseurl + str(i * 25)  # 转换成字符串，0时，0-25；1时，26-50.....
        html = askURL(url)  # 保存获取到的网页源码

    # TODO 2 逐一解析数据

        soup = BeautifulSoup(html, "html.parser")
        for item in soup.find_all('div', class_="item"):   # 查找符合要求的字符串，形成列表(class的属性是item，所以要加下划线)
            # print(item)  # 测试：查看电影item的全部信息
            data = []  # 保存一部电影的所有信息
            item = str(item)
            # print(item)     # 这里打印一部电影的详情，新建一个html文档，复制打印的内容，方便对比进行其他电影获取规则的设定（每一部电影内容都一样）
            # break

            # 获取电影详情的链接
            link = re.findall(findLink, item)[0]  # re库用来通过正则表达式查找指定的字符串   [0]可能会获取多个项目，只取第一个即可
            data.append(link)
            # print(link)
            # break


            imgSrc = re.findall(findImgSrc, item)[0]
            data.append(imgSrc)

            titles = re.findall(findTitle, item)   # title可能不止一个中文名，有的有中文和外文名
            if len(titles) == 2:
                ctitle = titles[0]   # 中文title
                data.append(ctitle)
                wtitle = titles[1].replace("/", "")  # 外文title，前面有个/，替换成“”，去掉无关的符号
                data.append(wtitle)
            else:
                data.append(titles[0])
                data.append(' ')   # 留空，如果没有外文名，就留个空

            rating = re.findall(findRating, item)[0]
            data.append(rating)

            judgeNum = re.findall(findJudge, item)[0]
            data.append(judgeNum)

            inq = re.findall(findInq, item)
            if len(inq) != 0:
                inq = inq[0].replace("。", "")
                data.append(inq)
            else:
                data.append(" ")   # 没有一句话概述，就留空

            bd = re.findall(findBd, item)[0]
            bd = re.sub('<br(\s+)?/>(\s+)?', " ", bd)    # 对bd进行操作：把其中的<br/>去掉，如果里面还有其他内容(\s+)？,/s匹配空白和tab键
            bd = re.sub('/', " ", bd)   # 去掉/
            data.append(bd.strip())   # 去掉bd前后的空格
            datalist.append(data)  # 把处理号的一部电影信息放入datalist
        # print(len(datalist))
    return datalist

# 得到一个指定的URL网页内容
def askURL(url):
    # 用户代理：告诉豆瓣服务器，我们是什么类型的机器、浏览器（本质上是告诉浏览器，我们可以接收什么水平的文件内容）
    # head：模拟浏览器头部信息，向豆瓣服务器发送消息
    head = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0"
    }
    request = urllib.request.Request(url, headers=head)
    html = ""  # 定义html
    try:
        response = urllib.request.urlopen(request)
        html = response.read().decode('utf-8')
        # print(html)
    except Exception as e:
        if hasattr(e, 'code'):     # has attributes:判断有无后面的属性，有返回Ture，否则返回False
            print(e.code)       # e.code(错误代码)，e.reason(获取错误的原因)
        if hasattr(e, 'reason'):
            print(e.reason)
    return html

# TODO 3 保存数据

def saveData(datalist):
    print("save......")
    book = xlwt.Workbook(encoding='utf-8', style_compression=0)
    sheet = book.add_sheet('豆瓣电影top250', cell_overwrite_ok=True)
    col = ("电影详情链接", "图片链接", "影片中文名", "影片外文名", "评分", "评价人数", "一句话概况", "相关内容")    # 列名为一个元组
    '''
    for i in range(0,8):
        sheet.write(0,i,col[i])
    book.save('ttt.xls')
    '''
    try:
        for i in range(0, 8):         # 有几个，写0-几
           sheet.write(0, i, col[i])      # 列名
        for i in range(0, 250):
            print(f"第{i+1}条")
            data = datalist[i]
            for j in range(0, 8):
                sheet.write(i+1, j, data[j])  # i+1:第二行开始写数据（第一行为列名）
        book.save("豆瓣电影Top250.xls")
    except Exception as e:
        print(f"出错了：{e}")
# print("save.......")

if __name__ == '__main__':
    main()